package com.hospital.common.handler;


import com.hospital.common.base.Result;
import com.hospital.common.exception.GlobalException;
import jakarta.validation.ConstraintViolationException;
import jakarta.validation.ValidationException;
import lombok.extern.slf4j.Slf4j;
import org.springframework.util.ObjectUtils;
import org.springframework.validation.BindException;
import org.springframework.web.HttpRequestMethodNotSupportedException;
import org.springframework.web.bind.MethodArgumentNotValidException;
import org.springframework.web.bind.MissingServletRequestParameterException;
import org.springframework.web.bind.annotation.ExceptionHandler;
import org.springframework.web.bind.annotation.RestControllerAdvice;
import org.springframework.web.method.annotation.MethodArgumentTypeMismatchException;

import java.util.Objects;

/**
 * 全局异常处理
 *
 * @author yhn
 * @version 1.0
 */
@RestControllerAdvice
@Slf4j
public class GlobalExceptionHandler {
    /**
     * 兜底异常处理
     * @param e 兜底异常
     * @return 错误信息
     */
    @ExceptionHandler(Exception.class)
    public Result<?> handleException(Exception e) {
        log.error("全局异常：{}", e.getMessage(), e);
        return Result.fail(e.getMessage());
    }

    /**
     * 全局业务异常处理
     * @param e 业务异常
     * @return 错误信息
     */
    @ExceptionHandler(GlobalException.class)
    public Result<?> handleGlobalException(GlobalException e) {
        log.error("服务异常：{}", e.getMessage(), e);
        return Result.fail(e.getCode(),e.getMessage());
    }

    /**
     * 参数缺失异常处理
     * @param e 参数缺失异常
     * @return 错误信息
     */
    @ExceptionHandler(MissingServletRequestParameterException.class)
    public Result<?> handleMissingServletRequestParameterException(MissingServletRequestParameterException e) {
        log.error("参数缺失异常：{}", e.getMessage(), e);
        return Result.fail(String.format("缺少参数：%s", e.getParameterName()));
    }

    /**
     * 参数类型错误异常处理
     * @param e 参数类型错误异常
     * @return 错误信息
     */
    @ExceptionHandler(MethodArgumentTypeMismatchException.class)
    public Result<?> handleMethodArgumentTypeMismatchException(MethodArgumentTypeMismatchException e) {
        log.error("参数类型错误异常：{}", e.getMessage(), e);
        return Result.fail(String.format("参数类型错误：%s", e.getMessage()));
    }

    /**
     * 参数校验异常处理
     * @param e 参数校验异常
     * @return 错误信息
     */
    @ExceptionHandler(MethodArgumentNotValidException.class)
    public Result<?> handleMethodArgumentNotValidException(MethodArgumentNotValidException e) {
        log.error("参数校验异常：{}", e.getMessage(), e);
        return Result.fail(Objects.requireNonNull(e.getBindingResult().getFieldError()).getDefaultMessage());
    }

    /**
     * Validator校验异常处理
     * @param e Validator校验异常
     * @return 错误信息
     */
    @ExceptionHandler(ConstraintViolationException.class)
    public Result<?> handleConstraintViolationException(ConstraintViolationException e) {
        log.error("Validator校验异常：{}", e.getMessage(), e);
        return Result.fail(String.format("参数验证错误：%s", e.getConstraintViolations().iterator().next().getMessage()));
    }

    /**
     * 参数绑定异常处理
     * @param e 参数绑定异常
     * @return 错误信息
     */
    @ExceptionHandler(BindException.class)
    public Result<?> handleBindException(BindException e) {
        log.error("参数绑定异常：{}", e.getMessage(), e);
        return Result.fail(Objects.requireNonNull(e.getFieldError()).getDefaultMessage());
    }

    /**
     * 参数验证异常处理
     * @param e 参数验证异常
     * @return 错误信息
     */
    @ExceptionHandler(ValidationException.class)
    public Result<?> handleValidationException(ValidationException e) {
        log.error("参数验证异常：{}", e.getMessage(), e);
        return Result.fail();
    }

    /**
     * 请求方式不支持异常处理
     * @param e 请求方式不支持异常
     * @return 错误信息
     */
    @ExceptionHandler(HttpRequestMethodNotSupportedException.class)
    public Result<?> handleHttpRequestMethodNotSupportedException(HttpRequestMethodNotSupportedException e) {
        log.error("不支持的请求方式：{}", e.getMessage(), e);
        return Result.fail(String.format("不支持的请求方式：%s", e.getMessage()));
    }

    /**
     * 运行时异常处理
     * <br>
     * 如果运行时异常的 cause 是 GlobalException，则返回 GlobalException 的错误码和错误信息
     * @param e 运行时异常
     * @return 错误信息
     */
    @ExceptionHandler(RuntimeException.class)
    public Result<?> handleRuntimeException(RuntimeException e) {
        log.error("运行时异常：{}", e.getMessage(), e);
        Throwable cause = e.getCause();
        if(!ObjectUtils.isEmpty(cause)){
            if(cause instanceof GlobalException){
                return Result.fail(((GlobalException) cause).getCode(), cause.getMessage());
            }
        }
        return Result.fail(e.getMessage());
    }
}
